# -*- coding: utf-8 -*-
"""
RBAC权限管理服务

动态权限管理，基于业务逻辑而非硬编码表关系：
- 动态权限计算和缓存
- 基于规则的权限判断
- 灵活的权限扩展机制
"""

from typing import List, Dict, Set, Optional, Any
from datetime import datetime, timedelta
import json
import logging
from sqlalchemy.orm import Session
from sqlalchemy import and_, or_

from ..models.rbac import User, Role, Permission, Resource, UserRole, RolePermission, UserPermission
from ..models.rbac import PermissionAction, ResourceType
from ..core.config import get_settings

logger = logging.getLogger(__name__)
settings = get_settings()


class PermissionRule:
    """权限规则定义"""
    
    def __init__(self, resource: str, action: str, conditions: Dict = None):
        self.resource = resource
        self.action = action
        self.conditions = conditions or {}
    
    def __str__(self):
        return f"{self.resource}:{self.action}"
    
    def matches(self, target_resource: str, target_action: str) -> bool:
        """检查规则是否匹配目标权限"""
        # 支持通配符匹配
        if self.resource == "*" or self.resource == target_resource:
            if self.action == "*" or self.action == target_action:
                return True
        
        # 支持模块级权限
        if target_resource.startswith(self.resource + "."):
            if self.action == "*" or self.action == target_action:
                return True
        
        return False


class DynamicPermissionManager:
    """动态权限管理器"""
    
    def __init__(self, db: Session):
        self.db = db
        self._permission_cache = {}
        self._cache_ttl = timedelta(minutes=15)
        self._last_cache_update = {}
    
    def get_user_permissions(self, user_id: int) -> Set[str]:
        """获取用户的所有权限（包括角色权限和直接权限）"""
        cache_key = f"user_perms_{user_id}"
        
        # 检查缓存
        if self._is_cache_valid(cache_key):
            return self._permission_cache[cache_key]
        
        permissions = set()
        
        # 1. 获取角色权限
        role_permissions = self._get_role_permissions(user_id)
        permissions.update(role_permissions)
        
        # 2. 获取直接权限
        direct_permissions = self._get_direct_permissions(user_id)
        permissions.update(direct_permissions)
        
        # 3. 处理权限继承和计算
        final_permissions = self._calculate_effective_permissions(permissions, user_id)
        
        # 缓存结果
        self._permission_cache[cache_key] = final_permissions
        self._last_cache_update[cache_key] = datetime.now()
        
        return final_permissions
    
    def _get_role_permissions(self, user_id: int) -> Set[str]:
        """获取用户的角色权限"""
        query = (
            self.db.query(Permission.code)
            .join(RolePermission, Permission.id == RolePermission.permission_id)
            .join(Role, RolePermission.role_id == Role.id)
            .join(UserRole, Role.id == UserRole.role_id)
            .filter(
                and_(
                    UserRole.user_id == user_id,
                    UserRole.is_active == True,
                    Role.is_active == True,
                    Permission.is_active == True,
                    RolePermission.is_granted == True,
                    # 检查权限是否在有效期内
                    or_(
                        UserRole.expires_at.is_(None),
                        UserRole.expires_at > datetime.now()
                    )
                )
            )
        )
        
        return set(code for code, in query.all())
    
    def _get_direct_permissions(self, user_id: int) -> Set[str]:
        """获取用户的直接权限"""
        query = (
            self.db.query(Permission.code)
            .join(UserPermission, Permission.id == UserPermission.permission_id)
            .filter(
                and_(
                    UserPermission.user_id == user_id,
                    UserPermission.is_active == True,
                    UserPermission.is_granted == True,
                    Permission.is_active == True,
                    or_(
                        UserPermission.expires_at.is_(None),
                        UserPermission.expires_at > datetime.now()
                    )
                )
            )
        )
        
        return set(code for code, in query.all())
    
    def _calculate_effective_permissions(self, base_permissions: Set[str], user_id: int) -> Set[str]:
        """计算有效权限（处理权限继承、拒绝等逻辑）"""
        effective_permissions = base_permissions.copy()
        
        # 1. 处理超级用户权限
        user = self.db.query(User).filter(User.id == user_id).first()
        if user and user.is_superuser:
            # 超级用户拥有所有权限
            all_permissions = self.db.query(Permission.code).filter(Permission.is_active == True).all()
            effective_permissions.update(code for code, in all_permissions)
        
        # 2. 处理权限拒绝（如果有拒绝权限的逻辑）
        denied_permissions = self._get_denied_permissions(user_id)
        effective_permissions -= denied_permissions
        
        # 3. 添加动态计算的权限
        dynamic_permissions = self._calculate_dynamic_permissions(user_id, effective_permissions)
        effective_permissions.update(dynamic_permissions)
        
        return effective_permissions
    
    def _get_denied_permissions(self, user_id: int) -> Set[str]:
        """获取被拒绝的权限"""
        # 查询明确拒绝的权限
        denied_role_perms = (
            self.db.query(Permission.code)
            .join(RolePermission, Permission.id == RolePermission.permission_id)
            .join(Role, RolePermission.role_id == Role.id)
            .join(UserRole, Role.id == UserRole.role_id)
            .filter(
                and_(
                    UserRole.user_id == user_id,
                    RolePermission.is_granted == False  # 明确拒绝
                )
            )
        )
        
        denied_user_perms = (
            self.db.query(Permission.code)
            .join(UserPermission, Permission.id == UserPermission.permission_id)
            .filter(
                and_(
                    UserPermission.user_id == user_id,
                    UserPermission.is_granted == False  # 明确拒绝
                )
            )
        )
        
        denied_perms = set()
        denied_perms.update(code for code, in denied_role_perms.all())
        denied_perms.update(code for code, in denied_user_perms.all())
        
        return denied_perms
    
    def _calculate_dynamic_permissions(self, user_id: int, base_permissions: Set[str]) -> Set[str]:
        """计算动态权限（基于业务规则）"""
        dynamic_perms = set()
        
        # 业务规则1：如果有读权限，自动获得基础查看权限
        if any(perm.endswith('.read') for perm in base_permissions):
            dynamic_perms.add('system.basic_view')
        
        # 业务规则2：管理权限包含所有CRUD权限
        for perm in base_permissions:
            if perm.endswith('.manage'):
                module = perm.split('.')[0]
                dynamic_perms.update([
                    f"{module}.read",
                    f"{module}.create", 
                    f"{module}.update",
                    f"{module}.delete"
                ])
        
        # 业务规则3：部门经理权限继承
        user = self.db.query(User).filter(User.id == user_id).first()
        if user and user.position and '经理' in user.position:
            # 经理自动获得本部门相关权限
            if user.department:
                dynamic_perms.add(f"department.{user.department.lower()}.manage")
        
        return dynamic_perms
    
    def check_permission(self, user_id: int, resource: str, action: str, context: Dict = None) -> bool:
        """检查用户是否有特定权限"""
        user_permissions = self.get_user_permissions(user_id)
        
        # 直接权限匹配
        permission_code = f"{resource}.{action}"
        if permission_code in user_permissions:
            return True
        
        # 规则匹配
        for perm in user_permissions:
            if self._permission_matches(perm, resource, action):
                # 进一步检查上下文条件
                if self._check_permission_conditions(user_id, perm, context):
                    return True
        
        return False
    
    def _permission_matches(self, permission: str, resource: str, action: str) -> bool:
        """检查权限是否匹配"""
        if '.' not in permission:
            return False
        
        perm_resource, perm_action = permission.rsplit('.', 1)
        
        # 完全匹配
        if perm_resource == resource and perm_action == action:
            return True
        
        # 通配符匹配
        if perm_action == '*' and perm_resource == resource:
            return True
        
        if perm_resource == '*':
            return True
        
        # 模块权限匹配子资源
        if resource.startswith(perm_resource + '.') and perm_action in [action, '*']:
            return True
        
        return False
    
    def _check_permission_conditions(self, user_id: int, permission: str, context: Dict = None) -> bool:
        """检查权限的附加条件"""
        if not context:
            return True
        
        # 获取权限的条件配置
        perm_obj = (
            self.db.query(Permission)
            .filter(Permission.code == permission)
            .first()
        )
        
        if not perm_obj or not perm_obj.conditions:
            return True
        
        try:
            conditions = json.loads(perm_obj.conditions)
            return self._evaluate_conditions(user_id, conditions, context)
        except (json.JSONDecodeError, Exception) as e:
            logger.warning(f"权限条件解析失败: {permission}, {e}")
            return True
    
    def _evaluate_conditions(self, user_id: int, conditions: Dict, context: Dict) -> bool:
        """评估权限条件"""
        # 数据权限：只能访问自己的数据
        if conditions.get('data_scope') == 'own':
            return context.get('owner_id') == user_id
        
        # 部门权限：只能访问本部门数据
        if conditions.get('data_scope') == 'department':
            user = self.db.query(User).filter(User.id == user_id).first()
            return context.get('department') == user.department
        
        # 时间权限：只在特定时间段有效
        if 'time_range' in conditions:
            now = datetime.now()
            start_time = datetime.strptime(conditions['time_range']['start'], '%H:%M')
            end_time = datetime.strptime(conditions['time_range']['end'], '%H:%M')
            current_time = now.time()
            return start_time.time() <= current_time <= end_time.time()
        
        return True
    
    def _is_cache_valid(self, cache_key: str) -> bool:
        """检查缓存是否有效"""
        if cache_key not in self._permission_cache:
            return False
        
        last_update = self._last_cache_update.get(cache_key)
        if not last_update:
            return False
        
        return datetime.now() - last_update < self._cache_ttl
    
    def invalidate_user_cache(self, user_id: int):
        """清除用户权限缓存"""
        cache_key = f"user_perms_{user_id}"
        self._permission_cache.pop(cache_key, None)
        self._last_cache_update.pop(cache_key, None)
    
    def get_user_accessible_resources(self, user_id: int, resource_type: ResourceType = None) -> List[Dict]:
        """获取用户可访问的资源列表"""
        user_permissions = self.get_user_permissions(user_id)
        
        # 查询所有资源
        query = self.db.query(Resource).filter(Resource.is_active == True)
        if resource_type:
            query = query.filter(Resource.type == resource_type)
        
        resources = query.all()
        accessible_resources = []
        
        for resource in resources:
            # 检查用户是否有访问该资源的权限
            has_access = False
            user_actions = []
            
            for action in PermissionAction:
                if self.check_permission(user_id, resource.code, action.value):
                    has_access = True
                    user_actions.append(action.value)
            
            if has_access:
                accessible_resources.append({
                    'id': resource.id,
                    'name': resource.name,
                    'code': resource.code,
                    'type': resource.type.value,
                    'path': resource.path,
                    'actions': user_actions
                })
        
        return accessible_resources


class PermissionDecorator:
    """权限装饰器"""
    
    @staticmethod
    def require_permission(resource: str, action: str):
        """权限检查装饰器"""
        def decorator(func):
            def wrapper(*args, **kwargs):
                # 从参数中获取当前用户
                current_user = kwargs.get('current_user')
                if not current_user:
                    raise PermissionError("未找到当前用户信息")
                
                # 检查权限
                from ..core.database import get_db
                db = next(get_db())
                permission_manager = DynamicPermissionManager(db)
                
                if not permission_manager.check_permission(
                    current_user.get('user_id'), 
                    resource, 
                    action,
                    context=kwargs.get('context')
                ):
                    raise PermissionError(f"权限不足: {resource}.{action}")
                
                return func(*args, **kwargs)
            return wrapper
        return decorator


# 全局权限管理器实例
def get_permission_manager(db: Session) -> DynamicPermissionManager:
    """获取权限管理器实例"""
    return DynamicPermissionManager(db)